/**
 * @file getSpecAttr
 * @description getSpecAttr
 * @author fanxueliang<fanxueliang
 */

import {UnionSpecItem} from '@jsw/report-core';
import {FlatSpecType, DatasourceType, SpecAttrConfigType} from '../interface';
import {
    get,
    map,
    cloneDeep,
    each,
    filter,
    includes,
    set,
    keys,
    omitBy,
    keyBy,
    isUndefined,
    isBoolean,
    isNil
} from 'lodash-es';
import {componentUi} from './enum';
import {ShallowObjectType} from '../hooks/util';
import {setNoRewriteAttrs} from './index';

// 以下是 spec直接属性
const needFilled = {
    label: '是否业务可见',
    component: componentUi.Switch,
    key: 'needFilled',
    path: 'needFilled'
};
const fieldRemove = {
    label: '是否删除当前节点',
    component: componentUi.Switch,
    key: 'fieldRemove',
    path: 'fieldRemove'
};
const displayName = {
    label: '表单项名称',
    component: componentUi.Input,
    key: 'displayName',
    path: 'displayName',
    attr: {
        placeholder: '最多8个汉字，告知用户填写的内容项',
        trim: true
    }
};
const selectDefaultValue = {
    label: '默认值',
    component: componentUi.Select,
    key: 'defaultValue',
    path: 'defaultValue',
    attr: {
        options: []
    }
};
const defaultValue = {
    label: '默认值',
    component: componentUi.Input,
    key: 'defaultValue',
    path: 'defaultValue',
    attr: {
        placeholder: '默认为用户填写的内容，写高频值或不填'
    }
};
const boolDefaultValue = {
    label: '默认值',
    component: componentUi.Switch,
    key: 'defaultValue',
    path: 'defaultValue'
};
const numberDefaultValue = {
    label: '默认值',
    component: componentUi.NumberInput,
    key: 'defaultValue',
    path: 'defaultValue',
    attr: {
        placeholder: '默认为用户填写的内容，写高频值或不填',
        precision: undefined
    }
};
const readOnly = {
    label: '是否只读',
    component: componentUi.Switch,
    key: 'readOnly',
    path: 'readOnly'
};

const disabled = {
    label: '是否禁用',
    component: componentUi.Switch,
    key: 'disabled',
    path: 'disabled'
};
const display = {
    label: '表单项背景配置',
    component: componentUi.Select,
    key: 'display',
    path: 'display',
    attr: {
        options: [
            {
                label: '显示背景色块',
                value: 'toggle-block'
            },
            {
                label: '隐藏表单项',
                value: 'none'
            },
            {
                label: '默认配置(跟随渲染组件)',
                value: ''
            }
        ]
    }
};
const tip = {
    label: '字段描述',
    component: componentUi.Textarea,
    attr: {
        placeholder: '显示在输入框下方。用于指导用户如何填写该字段'
    },
    key: 'tip',
    path: 'tip'
};
const nameTip = {
    label: '字段名解释',
    component: componentUi.Textarea,
    attr: {
        placeholder: '显示在问号浮层中，用于解释表单项名称的意义'
    },
    key: 'nameTip',
    path: 'nameTip'
};
const descriptionTip = {
    label: '强提示描述',
    component: componentUi.Textarea,
    attr: {
        placeholder: '直接显示在表单项下方的描述文本'
    },
    key: 'descriptionTip',
    path: 'descriptionTip'
};
const multiline = {
    label: '是否多行输入',
    component: componentUi.Switch,
    key: 'multiline',
    path: 'multiline'
};
const stringUi = {
    label: '展示组件',
    component: componentUi.Select,
    attr: {
        options: [
            {
                label: '文本输入组件（Input）',
                value: 'Input'
            },
            {
                label: '日期选择（DatePicker）',
                value: 'DatePicker'
            },
            {
                label: '自动完成输入组件（Autocomplete）',
                value: 'Autocomplete'
            }
        ],
        placeholder: '不选择时默认展示为文本输入组件'
    },
    key: 'ui',
    path: 'ui'
};

// 以下是spec extraAttr属性配置
// enum
const requireInitValue = {
    label: '是否自动计算默认选中项',
    component: componentUi.Switch,
    key: 'extraAttrreQuireInitValue',
    path: 'extraAttr.requireInitValue'
};
// upload
const maxSize = {
    label: '最大文件大小(kb)',
    component: componentUi.NumberInput,
    attr: {
        min: 0
    },
    key: 'extraAttrMaxSize',
    path: 'extraAttr.maxSize'
};
const ext = {
    label: '文件格式',
    component: componentUi.CheckboxGroupAdapter,
    attr: {
        items: [
            {
                label: 'jpeg',
                value: 'jpeg'
            },
            {
                label: 'jpg',
                value: 'jpg'
            },
            {
                label: 'png',
                value: 'png'
            },
            {
                label: 'gif',
                value: 'gif'
            }
        ]
    },
    key: 'extraAttrExt',
    path: 'extraAttr.ext'
};
const audioExt = {
    label: '文件格式',
    component: componentUi.CheckboxGroupAdapter,
    attr: {
        items: [
            {
                label: 'mp3',
                value: 'mp3'
            },
            {
                label: 'wav',
                value: 'wav'
            },
            {
                label: 'ogg',
                value: 'ogg'
            },
            {
                label: 'aac',
                value: 'aac'
            },
            {
                label: 'wma',
                value: 'wma'
            },
            {
                label: 'ra',
                value: 'ra'
            },
            {
                label: 'ape',
                value: 'ape'
            }
        ]
    },
    key: 'extraAttrExt',
    path: 'extraAttr.ext'
};
const width = {
    label: '宽度（px）',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 10000
    },
    key: 'extraAttrWidth',
    path: 'extraAttr.width'
};
const height = {
    label: '高度（px）',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 10000
    },
    key: 'extraAttrHeight',
    path: 'extraAttr.height'
};
const minWidth = {
    label: '最小宽度（px）',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 10000
    },
    key: 'extraAttrMinWidth',
    path: 'extraAttr.minWidth'
};
const minHeight = {
    label: '最小高度（px）',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 10000
    },
    key: 'extraAttrMinHeight',
    path: 'extraAttr.minHeight'
};
const maxWidth = {
    label: '最大宽度（px）',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 10000
    },
    key: 'extraAttrMaxWidth',
    path: 'extraAttr.maxWidth'
};
const maxHeight = {
    label: '最大高度（px）',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 10000
    },
    key: 'extraAttrMaxHeight',
    path: 'extraAttr.maxHeight'
};
const ratio = {
    label: '宽高比',
    component: componentUi.Select,
    attr: {
        options: []
    },
    key: 'extraAttrRatio',
    path: 'extraAttr.ratio'
};
const maxCount = {
    label: '最大上传个数',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 100
    },
    key: 'extraAttrMaxCount',
    path: 'extraAttr.maxCount'
};
// video
const videoSize = {
    label: '文件体积范围（mb）',
    component: componentUi.RangeAdapter,
    key: 'extraAttrSize',
    path: 'extraAttr.size'
};

const videoDuration = {
    label: '播放时长范围（s）',
    component: componentUi.RangeAdapter,
    key: 'extraAttrDuration',
    path: 'extraAttr.duration'
};

// list
const initialCount = {
    label: '默认显示个数',
    component: componentUi.NumberInput,
    attr: {
        min: 0,
        max: 100
    },
    key: 'extraAttrInitialCount',
    path: 'extraAttr.initialCount'
};
// color
const presetColors = {
    label: '预设颜色色值',
    component: componentUi.PresetColors,
    key: 'extraAttrColorConfigPresetColors',
    path: 'extraAttr.colorConfig.presetColors'
};
const allowCustom = {
    label: '允许自定义色值',
    component: componentUi.Switch,
    key: 'extraAttrColorConfigAllowCustom',
    path: 'extraAttr.colorConfig.allowCustom'
};
const defaultEnumValues = {
    label: '可见选项',
    component: componentUi.CheckboxGroup,
    attr: {
        items: []
    },
    key: 'pickEnumValues',
    path: 'pickEnumValues'
};
const diyEnumValues = {
    label: '可选选项',
    component: componentUi.EnumValuesAdapter,
    key: 'enumValues',
    path: 'enumValues'
};
const actionLinkPickValue = {
    label: '可见选项',
    component: componentUi.ActionLinkAdapter,
    attr: {
        items: []
    },
    key: 'actionLinkPickValue',
    path: 'actionLinkPickValue'
};
const tags = {
    label: 'tags',
    component: componentUi.CheckboxGroup,
    attr: {
        items: []
    },
    key: 'extraAttrTags',
    path: 'extraAttr.tags'
};
// html
const allowItalicTag = {
    label: '是否支持文本飘蓝',
    component: componentUi.Switch,
    key: 'extraAttrEditorConfigAllowItalicTag',
    path: 'extraAttr.editorConfig.allowItalicTag'
};

const normalAttr = [needFilled, display, fieldRemove, displayName, readOnly, disabled, nameTip, descriptionTip];

const getTagsDatasource = (spec: UnionSpecItem) => {
    const tags: string[] = get(spec, 'extraAttr.tags', []);
    let datasource: DatasourceType[] = [];
    if (tags && tags.length) {
        datasource = map(tags, (value) => {
            return {label: value, value};
        });
    }
    return datasource;
};

const getRatioDatasource = (spec: UnionSpecItem) => {
    const ratioList: string[] = get(spec, 'extraAttr.ratioList', []);
    let datasource: DatasourceType[] = [];
    if (ratioList && ratioList.length) {
        datasource = map(ratioList, (value) => {
            return {label: value, value};
        });
    }
    return datasource;
};

const getEnumValuesDatasource = (spec: UnionSpecItem) => {
    const defaultEnumValues: string[] = get(spec, 'extraAttr.defaultEnumValues', []);
    let enumValues: {value: string; displayName: string}[] = get(spec, 'enumValues', []);
    if (defaultEnumValues?.length) {
        enumValues = filter(enumValues, ({value}) => includes(defaultEnumValues, value));
    }
    let datasource: DatasourceType[] = [];
    if (enumValues && enumValues.length) {
        datasource = map(enumValues, ({value, displayName}) => {
            return {label: displayName, value};
        });
    }
    return datasource;
};

export const getSpecAttr = (flatSpecItem: FlatSpecType, actionLinkList: DatasourceType[]) => {
    const {spec, modifySpec} = cloneDeep(flatSpecItem);
    const {dataType} = spec;
    let realDefaultValue: boolean | number | undefined | string;
    realDefaultValue = get(spec, 'defaultValue');
    switch (dataType) {
        case 'STRING':
            set(flatSpecItem, 'specConfig.attr', [
                ...normalAttr,
                tip,
                defaultValue,
                multiline,
                stringUi,
                diyEnumValues
            ]);
            set(flatSpecItem, 'specConfig.extraAttr', []);
            break;
        case 'COLOR':
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, defaultValue]);
            set(flatSpecItem, 'specConfig.extraAttr', [presetColors, allowCustom]);
            break;
        case 'BOOL':
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, boolDefaultValue]);
            set(flatSpecItem, 'specConfig.extraAttr', []);
            realDefaultValue = isBoolean(spec.defaultValue) ? spec.defaultValue : spec.defaultValue === 'true';
            break;
        case 'NUMBER':
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, tip, numberDefaultValue]);
            if (spec.defaultValue) {
                realDefaultValue = +spec.defaultValue;
            }
            set(flatSpecItem, 'specConfig.extraAttr', []);
            break;
        case 'AUDIO':
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, defaultValue]);
            set(flatSpecItem, 'specConfig.extraAttr', [maxSize, audioExt]);
            break;
        case 'UPLOAD':
            const uploadRatio = cloneDeep(ratio);
            set(uploadRatio, 'attr.options', getRatioDatasource(spec));
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, defaultValue]);
            const imgExtraAttr = [maxSize, ext, width, height, minWidth, minHeight, maxWidth, maxHeight, uploadRatio];
            if (get(spec, 'extraAttr.multiple')) {
                imgExtraAttr.push(maxCount);
            }
            set(flatSpecItem, 'specConfig.extraAttr', imgExtraAttr);
            break;
        case 'VIDEO':
            const videoRatio = cloneDeep(ratio);
            set(videoRatio, 'attr.options', getRatioDatasource(spec));

            set(flatSpecItem, 'specConfig.attr', [...normalAttr, tip, defaultValue]);
            set(flatSpecItem, 'specConfig.extraAttr', [
                videoSize,
                videoDuration,
                width,
                height,
                minWidth,
                minHeight,
                maxWidth,
                maxHeight,
                videoRatio
            ]);
            break;
        case 'HTML':
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, tip, defaultValue]);
            set(flatSpecItem, 'specConfig.extraAttr', [allowItalicTag]);
            break;
        case 'URL':
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, tip, defaultValue]);
            set(flatSpecItem, 'specConfig.extraAttr', []);
            break;
        case 'ENUM':
            const enumSelectDefaultValue = cloneDeep(selectDefaultValue);
            const enumSelectDefaultValueOptions = getEnumValuesDatasource(spec);
            set(enumSelectDefaultValue, 'attr.options', enumSelectDefaultValueOptions);
            const enumValues = cloneDeep(defaultEnumValues);
            const enumValuesList = getEnumValuesDatasource(spec);
            set(enumValues, 'attr.items', enumValuesList);
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, tip, enumValues, enumSelectDefaultValue]);
            set(flatSpecItem, 'specConfig.extraAttr', [requireInitValue]);
            break;
        case 'OBJECT':
            set(flatSpecItem, 'specConfig.attr', [...normalAttr]);
            set(flatSpecItem, 'specConfig.extraAttr', []);
            break;
        case 'LIST':
            set(flatSpecItem, 'specConfig.attr', [needFilled, displayName, readOnly, disabled]);
            set(flatSpecItem, 'specConfig.extraAttr', [initialCount]);
            break;
        case 'ALTERNATIVE':
            const alterSelectDefaultValueAttr = cloneDeep(selectDefaultValue);
            const alterSelectDefaultValueOptions = getEnumValuesDatasource(spec);
            set(alterSelectDefaultValueAttr, 'attr.options', alterSelectDefaultValueOptions);
            const alterEnumValues = cloneDeep(defaultEnumValues);
            const alterEnumValuesList = getEnumValuesDatasource(spec);
            set(alterEnumValues, 'attr.items', alterEnumValuesList);
            set(flatSpecItem, 'specConfig.attr', [...normalAttr, alterEnumValues, alterSelectDefaultValueAttr]);
            set(flatSpecItem, 'specConfig.extraAttr', [requireInitValue]);
            break;
        // case 'ACTIONLINK':
        //     const actionLinkDefaultValueAttr = cloneDeep(selectDefaultValue);
        //     set(actionLinkDefaultValueAttr, 'attr.options', cloneDeep(actionLinkList));
        //     const actionLinkEnumValues = cloneDeep(actionLinkPickValue);
        //     set(actionLinkEnumValues, 'attr.items', cloneDeep(actionLinkList));
        //     set(flatSpecItem, 'specConfig.attr', [...normalAttr, actionLinkEnumValues, actionLinkDefaultValueAttr]);
        //     set(flatSpecItem, 'specConfig.extraAttr', []);
        //     break;
        default:
            throw new Error(`dataType ${dataType} is unknown!`);
    }

    const tagsDatasource = getTagsDatasource(spec);
    if (tagsDatasource.length) {
        const extraAttrTags = cloneDeep(tags);
        set(extraAttrTags, 'attr.items', tagsDatasource);
        flatSpecItem.specConfig?.extraAttr.push(extraAttrTags as SpecAttrConfigType);
    }

    let attrList = cloneDeep(get(flatSpecItem, 'specConfig.attr', []));
    let extraAttrList = cloneDeep(get(flatSpecItem, 'specConfig.extraAttr', []));
    // 禁用不可配置项
    const noRewriteAttrs = get(spec, 'extraAttr.noRewriteAttrs', []);
    if (noRewriteAttrs.length) {
        // attr 禁用不可配置项
        attrList = setNoRewriteAttrs(attrList, noRewriteAttrs);
        set(flatSpecItem, 'specConfig.attr', attrList);
        // extraAttr 禁用不可配置项
        extraAttrList = setNoRewriteAttrs(extraAttrList, noRewriteAttrs);
        set(flatSpecItem, 'specConfig.extraAttr', extraAttrList);
    }
    const attrKeys = map(attrList, (it) => ({key: it.key, path: it.path}));
    const attrModel: ShallowObjectType<any> = {};
    each(attrKeys, ({key, path}) => {
        let value;
        if (!key || !path) {
            return;
        }
        let modifyValue = get(modifySpec, path);
        if (modifyValue === -1 || modifyValue === '') {
            modifyValue = null;
        }
        if (key === 'actionLinkPickValue') {
            // actionlink 默认选中 默认配置
            value = !isUndefined(modifyValue) ? modifyValue : {type: 'default', values: []};
        } else if (key === 'defaultValue') {
            value = !isUndefined(modifyValue) ? modifyValue : realDefaultValue;
        } else {
            value = !isUndefined(modifyValue) ? modifyValue : get(spec, path);
        }
        set(attrModel, key, path ? value : null);
    });
    set(flatSpecItem, 'specConfig.attrModel', attrModel);
    const attrMap = keyBy(attrList, 'key');
    set(flatSpecItem, 'specConfig.attrMap', attrMap);
    const extraAttrMap = keyBy(extraAttrList, 'key');
    set(flatSpecItem, 'specConfig.extraAttrMap', extraAttrMap);
    // 已经存在的属性
    const inAttrModelKeys = keys(omitBy(attrModel, (it) => isNil(it)));
    // 不管是否有设置默认值，都开放默认值配置
    inAttrModelKeys.push('defaultValue');
    const inAttrList = filter(attrList, (it) => includes(inAttrModelKeys, it.key));
    set(flatSpecItem, 'specConfig.inAttrList', inAttrList);
    // 可以新增的属性
    const addableAttrList = filter(attrList, (it) => !includes(inAttrModelKeys, it.key));
    set(flatSpecItem, 'specConfig.addableAttrList', addableAttrList);

    const extraAttrKeys = map(extraAttrList, (it) => ({
        key: it.key,
        path: it.path
    }));
    const extraAttrModel: ShallowObjectType<any> = {};
    each(extraAttrKeys, ({key, path}) => {
        if (!key || !path) {
            return;
        }
        let modifyValue = get(modifySpec, path);
        if (modifyValue === -1 || modifyValue === '') {
            modifyValue = null;
        }
        const value = !isUndefined(modifyValue) ? modifyValue : get(spec, path);
        set(extraAttrModel, key, path ? value : null);
    });
    set(flatSpecItem, 'specConfig.extraAttrModel', extraAttrModel);
    // 已经存在的额外属性
    const inExtraAttrModelKeys = keys(omitBy(extraAttrModel, (it) => isNil(it)));
    const inExtraAttrList = filter(extraAttrList, (it) => includes(inExtraAttrModelKeys, it.key));
    set(flatSpecItem, 'specConfig.inExtraAttrList', inExtraAttrList);
    // 可以新增的额外属性
    const addableExtraAttrList = filter(extraAttrList, (it) => !includes(inExtraAttrModelKeys, it.key));
    set(flatSpecItem, 'specConfig.addableExtraAttrList', addableExtraAttrList);

    return flatSpecItem;
};
